package primetest.impl.dao;

import java.io.IOException;
import java.io.Serializable;
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;

import javax.inject.Inject;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import primetest.dto.ChargeDto;
import primetest.impl.dao.ChargeDao;
import primetest.impl.dao.Transaction;

public class ChargeDao implements Serializable {

	/**
	 *
	 */
	private static final long serialVersionUID = 6551770662358620809L;

	private final Logger logger = LoggerFactory.getLogger(this.getClass());

	private static List<ChargeDto> allItems = null;
	private static HashMap<String, ChargeDto> map = null;

	private DoctorDao doctorDao;
	private PatientDao patientDao;
	private TreatmentRecordDao treatmentRecordDao;

	@Inject
	public ChargeDao(DoctorDao doctorDao, PatientDao patientDao, TreatmentRecordDao treatmentRecordDao) {
		this.doctorDao = doctorDao;
		this.patientDao = patientDao;
		this.treatmentRecordDao = treatmentRecordDao;
	}

	public List<ChargeDto> getAllList(Transaction transaction) throws IOException {
		if (allItems != null) {
			return allItems;
		}
		PreparedStatement prepareStatement = null;
		ResultSet resultSet = null;
		map = new HashMap<String, ChargeDto>();
		try {

			Connection connection = transaction.getResource(Connection.class);
			prepareStatement = connection.prepareStatement(GET_ALL);
			resultSet = prepareStatement.executeQuery();

			while (resultSet.next()) {
				ChargeDto chargeDto = makeChargeDto(transaction, resultSet);
				map.put(chargeDto.getKey(), chargeDto);
			}
			allItems = new ArrayList<ChargeDto>(map.values());
			return allItems;
		} catch (SQLException e) {
			throw new IOException(e);
		} finally {
			if (resultSet != null) {
				try {
					resultSet.close();
				} catch (SQLException e) {
					logger.warn(e.getMessage(), e);
				}
			}

			if (prepareStatement != null) {
				try {
					prepareStatement.close();
				} catch (SQLException e) {
					logger.warn(e.getMessage(), e);
				}
			}
		}
	}

	private ChargeDto makeChargeDto(Transaction transaction,
			ResultSet resultSet) throws SQLException, IOException {
		ChargeDto chargeDto = new ChargeDto();
		chargeDto.setKey(resultSet.getString(1));
		chargeDto.setDoctorDto(doctorDao.findDoctor(transaction, resultSet.getInt(2)));
		chargeDto.setPatientDto(patientDao.getPatient(transaction, resultSet.getInt(3)));
		chargeDto.setFee(resultSet.getFloat(4));
		chargeDto.setGenDate(resultSet.getDate(5));
		chargeDto.setPayDate(resultSet.getDate(6));
		chargeDto.setStatus(resultSet.getInt(7));
		chargeDto.setType(resultSet.getInt(8));
		chargeDto.setSeq(resultSet.getInt(9));
		chargeDto.setDescription(resultSet.getString(10));
		if (chargeDto.isTreatmentRecordCharge()) {
			chargeDto.setTreatmentRecordDto(treatmentRecordDao.getTreatmentRecord(transaction, chargeDto.getSeq()));
		}
		return chargeDto;
	}

	public void addCharge(Transaction transaction, ChargeDto chargeDto)
			throws IOException {
		if (map == null) {
			getAllList(transaction);
		}
		PreparedStatement prepareStatement = null;
		ResultSet resultSet = null;
		try {
			Connection connection = transaction.getResource(Connection.class);
			prepareStatement = connection.prepareStatement(INSERT_ONE);
			prepareStatement.setString(1, chargeDto.getKey());
			prepareStatement.setInt(2, chargeDto.getDoctorSeq());
			prepareStatement.setInt(3, chargeDto.getPatientSeq());
			prepareStatement.setFloat(4, chargeDto.getFee());
			prepareStatement.setDate(5, new java.sql.Date(chargeDto.getGenDate().getTime()));
			prepareStatement.setDate(6, new java.sql.Date(chargeDto.getPayDate().getTime()));
			prepareStatement.setInt(7, chargeDto.getStatus());
			prepareStatement.setInt(8, chargeDto.getType());
			prepareStatement.setInt(9, chargeDto.getSeq());
			prepareStatement.setString(10, chargeDto.getDescription());
			prepareStatement.executeUpdate();
			map.put(chargeDto.getKey(), chargeDto);
			allItems.add(chargeDto);
		} catch (SQLException e) {
			throw new IOException(e);
		} finally {
			if (resultSet != null) {
				try {
					resultSet.close();
				} catch (SQLException e) {
					logger.warn(e.getMessage(), e);
				}
			}

			if (prepareStatement != null) {
				try {
					prepareStatement.close();
				} catch (SQLException e) {
					logger.warn(e.getMessage(), e);
				}
			}
		}
	}

	public ChargeDto findCharge(Transaction transaction, String key) throws IOException {
		if (map == null) {
			getAllList(transaction);
		}
		return map.get(key);
	}

	public void updateCharge(Transaction transaction, ChargeDto chargeDto)
			throws IOException {
		PreparedStatement prepareStatement = null;
		ResultSet resultSet = null;
		allItems = null;

		try {
			Connection connection = transaction.getResource(Connection.class);
			prepareStatement = connection.prepareStatement(UPDATE_ONE);
			prepareStatement.setString(10, chargeDto.getKey());
			prepareStatement.setInt(1, chargeDto.getDoctorSeq());
			prepareStatement.setInt(2, chargeDto.getPatientSeq());
			prepareStatement.setFloat(3, chargeDto.getFee());
			prepareStatement.setDate(4, new java.sql.Date(chargeDto.getGenDate().getTime()));
			prepareStatement.setDate(5, new java.sql.Date(chargeDto.getPayDate().getTime()));
			prepareStatement.setInt(6, chargeDto.getStatus());
			prepareStatement.setInt(7, chargeDto.getType());
			prepareStatement.setInt(8, chargeDto.getSeq());
			prepareStatement.setString(9, chargeDto.getDescription());
			prepareStatement.executeUpdate();
			map.put(chargeDto.getKey(), chargeDto);
			allItems = new ArrayList<ChargeDto>(map.values());
		} catch (SQLException e) {
			throw new IOException(e);
		} finally {
			if (resultSet != null) {
				try {
					resultSet.close();
				} catch (SQLException e) {
					logger.warn(e.getMessage(), e);
				}
			}

			if (prepareStatement != null) {
				try {
					prepareStatement.close();
				} catch (SQLException e) {
					logger.warn(e.getMessage(), e);
				}
			}
		}

	}

	public void deleteCharge(Transaction transaction, String chargeSeq)
			throws IOException {
		PreparedStatement prepareStatement = null;
		ResultSet resultSet = null;

		try {
			Connection connection = transaction.getResource(Connection.class);
			prepareStatement = connection.prepareStatement(DELETE_ONE);
			prepareStatement.setString(1, chargeSeq);
			prepareStatement.executeUpdate();
			allItems.remove(map.remove(chargeSeq));
		} catch (SQLException e) {
			throw new IOException(e);
		} finally {
			if (resultSet != null) {
				try {
					resultSet.close();
				} catch (SQLException e) {
					logger.warn(e.getMessage(), e);
				}
			}

			if (prepareStatement != null) {
				try {
					prepareStatement.close();
				} catch (SQLException e) {
					logger.warn(e.getMessage(), e);
				}
			}
		}

	}

	private static final String GET_ALL = "select key_1, doctor_seq, patient_seq, fee, gen_date, pay_date, status, type_1, seq, description from s_charge order by gen_date";
	private static final String INSERT_ONE = "insert into s_charge(key_1, doctor_seq, patient_seq, fee, gen_date, pay_date, status, type_1, seq, description) values (?, ?, ?, ?, ?, ?, ?, ?, ?, ?)";
	private static final String UPDATE_ONE = "update s_charge set doctor_seq = ?, patient_seq = ?, fee = ?, gen_date = ?, pay_date = ?, status = ?, type_1 = ?, seq = ?, description = ?" +
			" where key_1 = ?";
	private static final String DELETE_ONE = "delete from s_charge where key_1 = ?";
}
